/*----------------------------------------------------------------------------*/
/* Copyright 2020-2021 NXP                                                    */
/*                                                                            */
/* NXP Confidential. This software is owned or controlled by NXP and may only */
/* be used strictly in accordance with the applicable license terms.          */
/* By expressly accepting such terms or by downloading, installing,           */
/* activating and/or otherwise using the software, you are agreeing that you  */
/* have read, and that you agree to comply with and are bound by, such        */
/* license terms. If you do not agree to be bound by the applicable license   */
/* terms, then you may not retain, install, activate or otherwise use the     */
/* software.                                                                  */
/*----------------------------------------------------------------------------*/

/** \file
*
* Example Source for NfcrdlibEx10_MIFAREDESFire_EVx that demonstrates communication
* with MIFARE DESFire EV2 contactless IC and MIFARE DESFire EV3 contactless IC cards.
* This example will Detect and activater the Type-A card.
* If card is MIFAREDESFire EV2 and MIFAREDESFire EV3 then it will format the card and create application
* After creating application, it will create one Standard File. It will
* demo read and write operations with the card.
* KEYTYPE is AES.
* Please refer Readme.txt file for Hardware Pin Configuration, Software Configuration and steps to build and
* execute the project which is present in the same project directory.
*
* $Author$
* $Revision$ (v07.02.00)
* $Date$
*
*/

/**
* Reader Library Headers
*/
#include <phApp_Init.h>
#include "BSP.h"
#include "log/log2.h"
#include <Utility.h>

#include <Reader/Reader.h>
#include "phpalCt/phpalCt.h"
#include "phalMfdfEVx.h"


/* *****************************************************************************************************************
* MACROS/Defines
* ***************************************************************************************************************** */
#define PH_EXMFCRYPTO_MFDFCRYPTO_MIFAREDESFIRE_SAK      0x20

#define AES128_KEY_ADDRESS       0       /* PICC Key entry number in key store. */
#define AES128_KEY_VERSION       0       /* PICC Key entry number in key store. */

#define PICC_MASTER_KEY          0
#define APP_MASTER_KEY           0

#define SAM_MASTER_KEY			 0
#define SAM_MASTER_KEY_VERSION	 0

#define KEYCOUNT				 1
#define KEYVERSIONS 			 1

#define PH_EX10_CARD_REMOVED_CHK_CNT  5

#define SAM_LC0         0x00U /**< SAM logical channel 0 */

#define PH_EXCT7816_MAX_ATR_SIZE         33
#define PH_EXCT7816_MAX_NO_APDU          6
#define PH_EXCT7816_APDU_LENGTH          13

#define DESFIRE_DEFAULT 			0x01
#define DESFIRE_DEFAULT_AES			0x02

#define APPLE_KEY_ID_DES			0x21
#define APPLE_KEY_ID_AES			0x22

#define GOOGLE_KEY_ID_AES			0x23

#define SAM_AV3_GET_VERSION_STATE					30
#define SAM_AV3_GET_VERSION_STATE_UNACTIVATED		0x03

/*******************************************************************************
**   Global Variable Declaration
*******************************************************************************/

phacDiscLoop_Sw_DataParams_t       * pDiscLoop;     /* Pointer to Discovery loop data-params */
phpalI14443p3a_Sw_DataParams_t     * ppalI14443p3a; /* Pointer to PAL 14443-3A data-params */
phpalI14443p4_Sw_DataParams_t      * ppalI14443p4;  /* Pointer to PAL 14443-4 data-params */
phKeyStore_Sw_DataParams_t  	   * pKeyStore;
//phalMfdfEVx_Sw_DataParams_t        * palMfdfEVx;    /* Pointer to MIFAREDESFire Ev2 data-params */
phpalMifare_Sw_DataParams_t			*ppalMifare;


phKeyStore_Sw_KeyEntry_t       keyEntry[KEYCOUNT];
phKeyStore_Sw_KeyVersionPair_t keyVersion[KEYCOUNT * KEYVERSIONS];
phKeyStore_Sw_KUCEntry_t       keyUsage[KEYCOUNT];

extern phhalHw_SamAV3_DataParams_t stHal_SamAv3;
phCryptoSym_Sw_DataParams_t stCryptoEnc;
phCryptoSym_Sw_DataParams_t stCryptoMAC;
phCryptoSym_Sw_DataParams_t stCryptoSymRnd;
phCryptoRng_Sw_DataParams_t stCryptoRng;
phalMfdfEVx_SamAV3_NonX_DataParams_t  palMfdfEVx;	/* Pointer to MIFAREDESFire EVx data-params for SAM in S mode */
phTMIUtils_t						pTMI;


uint8_t aTx_SamBuffer[260];
uint8_t aRx_SamBuffer[260];

uint8_t aTMIBuffer[280];//Buffer for DESFire TMI collection
uint8_t aCmdBuffer[280];//Buffer for DESFire commands

#ifdef PHOSAL_FREERTOS_STATIC_MEM_ALLOCATION
uint32_t MfDesTaskBuffer[MIFAREDESFIRE_TASK_STACK];
#else /* PHOSAL_FREERTOS_STATIC_MEM_ALLOCATION */
#define MfDesTaskBuffer    NULL
#endif /* PHOSAL_FREERTOS_STATIC_MEM_ALLOCATION */



/* AES default key */
static uint8_t aAES128Key[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};



/*DESFire default Key entry*/
static uint8_t pDESFireDefault[] = {
		0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0xF5,0x32,0xF0,																					//DF_AID
		0x01,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x24, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};
		
/*apple_wallet Key entry*/
static uint8_t apple_wallet_key_des[] = {
		0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0x00,0x1E,0xA1,																					//DF_AID
		0x00,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x00, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};

static uint8_t apple_wallet_key_aes[] = {
		0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4,		//KeyValueA
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		0x01,0x1E,0xA1,																					//DF_AID
		0x00,																								//DF_KeyNo
		0x00, 0x00,																							//KeyNo and KeyV CEK
		0xFF,																								//no KUC
		0x24, 0x00,																							//SET
		0x00, 0x00, 0x00,																					//KeyVA,B,C
		0x01, 0x00,																							//EXTSet
		0x00, 0x00																							//KeyNo and KeyV AEK
};

/*===================================================================================*/
#pragma pack(1)
	typedef struct {
		uint8_t keys[3][16];
		uint8_t aid[3];
		uint8_t key_no;
		uint8_t kce_no,kce_ver;
		uint8_t kuc_no;
		uint16_t set;
		uint8_t key_ver[3];
		uint16_t ext_set;
		uint8_t kae_no,kae_ver;
	}sam_key_entry_t;

	typedef struct {
		uint8_t tag1;
		uint8_t length1;
		uint8_t tag2;
		uint8_t length2;
		uint8_t info;
		uint8_t pdcap[2];
		uint8_t vcuid[7];
		uint8_t version_id;
		uint8_t timestamp[5];
	}fci_info_t;

	typedef struct {
		uint8_t major;
		uint8_t minor;
		uint8_t customer_code[5];
		uint8_t credential_id[8];
		uint8_t reissue_code;
		uint8_t pin_code[4];
		uint8_t customer_data[20];
		uint8_t signature[8];
	}acd_ev1_t;

	typedef struct {
		uint16_t head;
		uint8_t data[8];
		uint8_t wg_num;
		uint8_t wg_format;
	}default_data_t;
	
	typedef struct {
		uint8_t wg_num;
		uint8_t wg_format;
		uint8_t data[18];
	}custom_data_t;
#pragma pack()
/*===================================================================================*/
/*DESFire default Key entry*/
static sam_key_entry_t google_wallet_key_entry = {
		.keys[0] = {0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0xF5,0x32,0xF0},																					//DF_AID
		.key_no = 0x01,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00024,																							//SET
		.key_ver = {0x01, 0x02, 0x03},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};

static sam_key_entry_t apple_wallet_key_entry_des = {
		.keys[0] = {0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x1E,0xA1},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00000,																							//SET
		.key_ver = {0x00, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};

static sam_key_entry_t apple_wallet_key_entry_aes = {
		.keys[0] = {0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19,	0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4},		//KeyValueA
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x01,0x1E,0xA1},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x00024,																							//SET
		.key_ver = {0x00, 0x00, 0x00},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
};
/*==============================================================================================================*/
// 默认密钥
static sam_key_entry_t factory_keys[3] = 
{
	//默认读密钥KFR0
	[0] = {
		.keys[0] = {0xD2,0x22,0x9A,0xC0,0xF6,0x9F,0xC8,0x4E,0x87,0x4F,0x2F,0x88,0xD5,0x52,0x5B,0xA6},		//KeyValueA
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x0024,																							//SET
		.key_ver = {0x01, 0x02, 0x03},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
	},
	//读密钥KFR
	[1] = {
		.keys[0] = {0xBF,0x84,0xB0,0xCC,0x39,0xD6,0xE1,0x53,0xE6,0x76,0x06,0xAF,0x46,0x5C,0x66,0x81},		//KeyValueA
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x0024,																							//SET
		.key_ver = {0x01, 0x02, 0x03},																					//KeyVA,B,C
		.ext_set = 0x0001,																							//EXTSet OfflineCrypto
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
	},
	//MAC密钥KFM
	[2] = {
	 	.keys[0] = {0x35,0x55,0x98,0x72,0x35,0xAA,0x4D,0xFB,0xF4,0xD8,0x35,0xC0,0x45,0xDF,0xDB,0x98},		//KeyValueA
//			.keys[0] = {0x7A,0x6B,0x47,0x73,0xE8,0x6C,0x1F,0x5A,0xB1,0x8D,0x06,0xE7,0xAC,0xF1,0x89,0x2D},		//KeyValueA
//			.keys[0] = {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},		//KeyValueA

		//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueB
	//			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 	//KeyValueC
		.aid = {0x00,0x00,0x00},																					//DF_AID
		.key_no = 0x00,																								//DF_KeyNo
		.kce_no = 0x00, .kce_ver = 0x00,																							//KeyNo and KeyV CEK
		.kuc_no = 0xFF,																								//no KUC
		.set = 0x0020,																							//SET
		.key_ver = {0x01, 0x02, 0x03},																					//KeyVA,B,C
		.ext_set = 0x0004,																							//EXTSet OfflineCrypto 
		.kae_no = 0x00, .kae_ver = 0x00																							//KeyNo and KeyV AEK
	},	
};

/*==============================================================================================================*/
/* *****************************************************************************************************************
* Types/Structure Declarations
* ***************************************************************************************************************** */
typedef struct _mf2go_param{
	uint8_t keys[16];
	uint8_t df_name[16];
	uint8_t aid[3];
	uint8_t file_no;
	uint8_t key_no;
	uint8_t key_type;
}w_mf2go_param_t;

typedef struct {
	uint8_t format;
	uint8_t terminal_info_mode;
	uint8_t type;
	uint8_t sub_type;
	uint8_t tci[3];
}ecp_param_t;

typedef struct {
	uint32_t aid;
	uint8_t keys[16];
	uint8_t key_type;
	uint8_t key_no;
	uint8_t diversified;
}key_set_t;

typedef struct _apple_wallet{
	key_set_t key_set[2];
	uint8_t file_no;
	uint8_t file_size;
}w_apple_wallet_param_t;

w_mf2go_param_t mf2go_param = {
	.keys = {0xD4,0x28,0x31,0xB1,0x16,0x43,0x68,0x44,0xD5,0xAE,0xD5,0x67,0xB1,0xDA,0x14,0xE2},
	.df_name = {0xa0, 0x00, 0x00, 0x03, 0x96, 0x56, 0x43, 0x41, 0x03, 0xf5, 0x32, 0xf0, 0x00, 0x02, 0x09, 0x01},
	.aid = {0xF5,0x32,0xF0},
	.file_no = 0x02,
	.key_no = 0x01,
	.key_type = PH_KEYSTORE_KEY_TYPE_AES128,
};

w_apple_wallet_param_t apple_wallet_param = {
	.key_set = {
		[0] = {
			.aid = 0xA11E00,
			.keys = {0x30, 0x84, 0x5e, 0xf6, 0x5b, 0x17, 0x25, 0x20, 
					0xb7, 0x57, 0x36, 0x01, 0x2c, 0x24, 0xd1, 0x16},
			.key_type = PH_KEYSTORE_KEY_TYPE_2K3DES,
			.key_no = 0x00,
			.diversified = 0,
		},
		[1] = {
			.aid = 0xA11E01,
			.keys = {0xab, 0x43, 0x7c, 0xb9, 0xf5, 0x9c, 0xb8, 0x19, 
					0xf6, 0x70, 0x9d, 0xc1, 0x8f, 0xea, 0xf0, 0xb4},
			.key_type = PH_KEYSTORE_KEY_TYPE_AES128,
			.key_no = 0x00,
			.diversified = 1,
		},
	},
	.file_no = 0x01,
	.file_size = 16,
};
/* *****************************************************************************************************************
* Function Prototypes
* ***************************************************************************************************************** */


/*******************************************************************************
**   Function Definitions
*******************************************************************************/
/* Utility function to print a buffer */
void PRINT_BUFFER(uint8_t * pBuffer, uint16_t wLength)
{
    uint16_t wIndex;

    for (wIndex = 0; wIndex < wLength; ++wIndex)
    {
        DEBUG_PRINTF("%02X ", pBuffer[wIndex]);
    }
    DEBUG_PRINTF("\n");
}

phStatus_t StoreKeysInKeyStore(phKeyStore_Sw_DataParams_t * pKeyStore)
{
    phStatus_t status;

    status = phKeyStore_FormatKeyEntry(pKeyStore, AES128_KEY_ADDRESS, PH_CRYPTOSYM_KEY_TYPE_AES128);
    CHECK_SUCCESS(status);

    return phKeyStore_SetKeyAtPos(pKeyStore, AES128_KEY_ADDRESS, 0x00, PH_CRYPTOSYM_KEY_TYPE_AES128,
            aAES128Key, AES128_KEY_VERSION);
}

int reader_wavelynx_init(void){
    phStatus_t  status = 0;
    uint16_t    wTechDetected = 0;
    uint8_t     bTagType;
    uint8_t     bCardRemoved = 0U;

    /** Instance for  CT pal parameter's structure */
	phpalCt_DataParams_t pDataParams ;

	/* Initialize library */
	
	/* Set the generic pointer */
	pHal = phNfcLib_GetDataParams(PH_COMP_HAL);
	pDiscLoop = (phacDiscLoop_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_AC_DISCLOOP);
	ppalI14443p3a = (phpalI14443p3a_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P3A);
	ppalI14443p4 = (phpalI14443p4_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4);
	pKeyStore = (phKeyStore_Sw_DataParams_t *)	phNfcLib_GetDataParams(PH_COMP_KEYSTORE);
	//palMfdfEVx = (phalMfdfEVx_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_AL_MFDFEVX);//Not needded
	ppalMifare= (phpalMifare_Sw_DataParams_t *) phNfcLib_GetDataParams(PH_COMP_PAL_MIFARE);
	
	phTMIUtils_Init(&pTMI,aTMIBuffer,sizeof(aTMIBuffer));
	
	//INIT DESFire Params
	  status = phalMfdfEVx_SamAV3_NonX_Init(
				&palMfdfEVx,
				sizeof(palMfdfEVx),
				&stHal_SamAv3,
				ppalMifare,
				&pTMI,
				aCmdBuffer,
				sizeof(aCmdBuffer)
			 );
	
	  if(status != PH_ERR_SUCCESS) {
			DEBUG_PRINTF("\n DESFire Init failed!");
			 DEBUG_ERROR_PRINT(status);
		 }
	
	phpalCt_Init();
    /** Check the card presence */
    DEBUG_PRINTF("Waiting for CT card insertion.\n");

	DEBUG_PRINTF("CT card detected\n");

    /* The response buffer is used to optimize the code */
	pDataParams.pbAtrBuffer = (uint8_t *)(&aRx_SamBuffer);
	pDataParams.bSizeOfATRbuffer = PH_EXCT7816_MAX_ATR_SIZE;

	/* Activate the card */
	status = phpalCt_ActivateCard(&pDataParams);
	if(PH_ERR_SUCCESS != status)
	{
		DEBUG_PRINTF("Card Activation failed.\n");
		DEBUG_ERROR_PRINT(status);
	}


	/** Initialize Crypto components. */
	phCryptoSym_Sw_Init(&stCryptoEnc, sizeof(phCryptoSym_Sw_DataParams_t), &pKeyStore);
	phCryptoSym_Sw_Init(&stCryptoMAC, sizeof(phCryptoSym_Sw_DataParams_t), &pKeyStore);
	phCryptoSym_Sw_Init(&stCryptoSymRnd, sizeof(phCryptoSym_Sw_DataParams_t), &pKeyStore);
	phCryptoRng_Sw_Init(&stCryptoRng, sizeof(phCryptoRng_Sw_DataParams_t), &stCryptoSymRnd);

	DEBUG_PRINTF("Card Activation Successful.\n");
	LOG2_BUF_INF("ATR:\n",pDataParams.pbAtrBuffer, pDataParams.bAtrReceivedLength);

    /* init. keystore */
    status = phKeyStore_Sw_Init(pKeyStore,
        sizeof(phKeyStore_Sw_DataParams_t),
        keyEntry,
        KEYCOUNT,
        keyVersion,
        KEYVERSIONS,
        keyUsage,
        KEYCOUNT);
    if(status != PH_ERR_SUCCESS) {
    	 DEBUG_PRINTF("\n Keystore Init failed!");
    	 DEBUG_ERROR_PRINT(status);
    }

    /* Set all the keys in the S/W key store */
    status = StoreKeysInKeyStore(pKeyStore);
    if(status != PH_ERR_SUCCESS) {
    	 DEBUG_PRINTF("\n store keys in keystore failed!");
    	 DEBUG_ERROR_PRINT(status);
    }
    /*Init RNG seed (take all 00s AES key Array)<- not production grade*/
    status = phCryptoRng_Seed(&stCryptoRng,&aAES128Key[0],0x10);
    if(status != PH_ERR_SUCCESS) {
       	 DEBUG_PRINTF("\n Rng Seed init failed!");
       	 DEBUG_ERROR_PRINT(status);
    }

	 /* Init SAM AV3 */
	 status = phhalHw_SamAV3_Init(
		&stHal_SamAv3,
		sizeof ( stHal_SamAv3 ),
		&pDataParams, //?phpalCt_DataParams_t pDataParams <-- isnt this a pal, not bal?
		pHal,
		pKeyStore,
		&stCryptoEnc,
		&stCryptoMAC,
		&stCryptoRng,
		NULL,
		NULL,
		PHHAL_HW_SAMAV3_OPMODE_NON_X,
		0x00,
		aTx_SamBuffer,
		sizeof ( aTx_SamBuffer ),
		aRx_SamBuffer,
		sizeof ( aRx_SamBuffer ),
		NULL
		);


	 if(status == PH_ERR_SUCCESS) {
		 DEBUG_PRINTF("\n SAM Init successful!");
	 }
	 else {
		DEBUG_PRINTF("\n SAM Init failed!");
		DEBUG_ERROR_PRINT(status);
	}

    /* SAM Get Version */
    uint8_t rxLen = 0;
    status = phhalHw_SamAV3_Cmd_SAM_GetVersion(
    		&stHal_SamAv3,
			aRx_SamBuffer,
			&rxLen);

    if(status != PH_ERR_SUCCESS) {
		DEBUG_PRINTF("\n SAM GetVersion failed!");
		DEBUG_ERROR_PRINT(status);
    }
    else{
    	 /* Print SAM Version */
    	DEBUG_PRINTF("\nSAM AV3 Get Version: ");
    	LOG2_BUF_INF("\t", aRx_SamBuffer, rxLen);
    }
	//TODO：为防止SAM 主密钥停用导致设备永久锁定，使用独立的lock密钥。详见9.3.1.2.1 Host key properties
	if(aRx_SamBuffer[SAM_AV3_GET_VERSION_STATE] == SAM_AV3_GET_VERSION_STATE_UNACTIVATED) {
		/* Activate SAM AV3 if not yet done */
		DEBUG_PRINTF("\nSAM LockUnlock: ");
		status = phhalHw_SamAV3_Cmd_SAM_LockUnlock(
				&stHal_SamAv3,
				PHHAL_HW_SAMAV3_CMD_SAM_LOCK_UNLOCK_TYPE_ACTIVATE_SAM,
				AES128_KEY_ADDRESS,
				AES128_KEY_VERSION,
				SAM_MASTER_KEY,
				SAM_MASTER_KEY_VERSION,
				0,
				0,
				0
		);

	}

	/* Perform HostAuth with SAM Master Key. */
	DEBUG_PRINTF("\nSAM Host Authentication: ");
#if 0
	status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
			&stHal_SamAv3,
			PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_PLAIN,
			AES128_KEY_ADDRESS,
			AES128_KEY_VERSION,
			SAM_MASTER_KEY,
			SAM_MASTER_KEY_VERSION
	);
#endif 
	status = phhalHw_SamAV3_Cmd_SAM_AuthenticateHost(
			&stHal_SamAv3,
			PHHAL_HW_SAMAV3_CMD_SAM_AUTHENTICATE_HOST_MODE_FULL,
			AES128_KEY_ADDRESS,
			AES128_KEY_VERSION,
			SAM_MASTER_KEY,
			SAM_MASTER_KEY_VERSION
	);

	if(status != PH_ERR_SUCCESS) {
		DEBUG_PRINTF(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		DEBUG_PRINTF(" successful!");
	}
	return status;
}

int reader_wavelynx_load_keys(void){
    phStatus_t  status = 0;
	/* Change Key Entry to type AES */
	LOG2_PRINT("\nGoogle AES key loading: ");
//		pDESFireDefault[55] = 0x24; //reuse of same array, just change setting to AES key (see datasheet)
//		status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, GOOGLE_KEY_ID_AES, 0xFF, &pDESFireDefault[0], 0x40);
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, GOOGLE_KEY_ID_AES, 0xFF, (uint8_t*)&google_wallet_key_entry, 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}
	LOG2_PRINT("\nApple DES key loading: ");
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, APPLE_KEY_ID_DES, 0xFF, (uint8_t*)&apple_wallet_key_entry_des, 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}
	LOG2_PRINT("\nApple AES key loading: ");
	status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, APPLE_KEY_ID_AES, 0xFF, (uint8_t*)&apple_wallet_key_entry_aes, 0x40);
	if(status != PH_ERR_SUCCESS) {
		LOG2_PRINT(" failed!");
		DEBUG_ERROR_PRINT(status);
	}
	else {
		LOG2_PRINT(" successful!");
	}

	return status;
}

/** *******
 * 装载默认密钥
 */
int reader_wavelynx_load_default_keys(void){
	phStatus_t  status = 0;
	LOG2_PRINT("\nFactory AES key loading: ");
	//默认密钥的数量
	int count = sizeof(factory_keys) / sizeof(sam_key_entry_t);
	for (size_t i = 0; i < count; i++)
	{
		status = phhalHw_SamAV3_Cmd_SAM_ChangeKeyEntry(&stHal_SamAv3, i+1, 0xFF, (uint8_t*)&factory_keys[i], 0x40);
		if(status != PH_ERR_SUCCESS) {
			LOG2_PRINT(" failed!");
			DEBUG_ERROR_PRINT(status);
		}
		else {
			LOG2_PRINT(" successful!");
		}
	}

	return status;
}

static void reader_get_access_data(uint8_t *customer_data, credential_t* cred){
	default_data_t* def_data = (default_data_t*)customer_data;
	if(def_data->head == 0x1001){
		//默认格式
		uint8_t len = def_data->wg_num / 8;
		if(def_data->wg_num & 0x07){
			len++;
		}
		cred->nbit = def_data->wg_num;
		cred->clen = len;
		Mem_Backward_Copy(cred->credential, len, def_data->data, sizeof(def_data->data), len);
	}
	else{
		//自定义格式
		custom_data_t* custom = (custom_data_t*)customer_data;
		uint8_t len = custom->wg_num / 8;
		if(custom->wg_num & 0x07){
			len++;
		}
		cred->nbit = custom->wg_num;
		cred->clen = len;
		Mem_Backward_Copy(cred->credential, len, custom->data, sizeof(custom->data), len);
	}
}

static void reader_print_fci(const fci_info_t* fci){
	LOG2_PRINT("\n===========FCI============\n");
	LOG2_PRINT("info: %02X\n", fci->info);
	LOG2_PRINT("pdcap: %02X%02X\n", fci->pdcap[0], fci->pdcap[1]);
	LOG2_PRINT("vcuid: %02X%02X%02X%02X%02X%02X%02X\n", fci->vcuid[0], fci->vcuid[1], 
		fci->vcuid[2], fci->vcuid[3], fci->vcuid[4], fci->vcuid[5], fci->vcuid[6]);
	LOG2_PRINT("version_id: %02X\n", fci->version_id);
	LOG2_PRINT("timestamp: %02X%02X%02X%02X%02X\n", fci->timestamp[0], fci->timestamp[1], 
		fci->timestamp[2], fci->timestamp[3], fci->timestamp[4]);
	LOG2_PRINT("===========================\n");
}

static uint8_t reader_mf2go_gen_div(const fci_info_t* fci, const uint8_t aid[3], uint8_t *div){
	uint8_t len = 0;
//		div[len++] = 0x01;
	memcpy(&div[len], fci->vcuid, sizeof(fci->vcuid));
	len += sizeof(fci->vcuid);
	memcpy(&div[len], aid, 3);
	len += 3;
	div[len++] = fci->info;
	memcpy(&div[len], fci->timestamp, sizeof(fci->timestamp));
	len += sizeof(fci->timestamp);
	return len;
}

static uint32_t reader_read_google_wallet(w_mf2go_param_t* param, credential_t* cred){
		phStatus_t status;
	
		uint8_t versionInfo[28];
		uint8_t *AID = param->aid;
//			uint8_t *ISODFName = param->df_name;
		phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
		/* Clear the console. */
		log_reset_level();
		LOG2_DBG("A Ticket is discovered \n");
	
		
		/* SelectApplication */
		LOG2_PRINT("\nDESFire Select application.");
	fci_info_t fci_info = {0};
	{
		uint8_t *pFCI = NULL;
		uint16_t wFCILen = 0;
		status = phalMfdfEVx_IsoSelectFile(pAlMfdfEVx, 
			PHAL_MFDFEVX_FCI_RETURNED, 
			PHAL_MFDFEVX_SELECTOR_4,
			NULL,
			param->df_name, sizeof(param->df_name),
			0,
			&pFCI, &wFCILen
			);
		CHECK_SUCCESS(status);
		LOG2_BUF_DBG("FCI", pFCI, wFCILen);
		uint8_t len = wFCILen < sizeof(fci_info) ? wFCILen : sizeof(fci_info);
		memcpy(&fci_info, pFCI, len);
		reader_print_fci(&fci_info);
	}
	
		uint8_t div[32] = {0};
		uint8_t dlen = reader_mf2go_gen_div(&fci_info, AID, div);
		
		LOG2_BUF_DBG("div", div, dlen);
		uint8_t key_no = param->key_no;
		LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
		/*AES Authenticate First*/
		status = phalMfdfEVx_AuthenticateAES(
				pAlMfdfEVx,
				PHAL_MFDFEVX_DIV_METHOD_CMAC,
				GOOGLE_KEY_ID_AES,
				0x00,
				key_no,
				div,
				dlen);
		 CHECK_SUCCESS(status);
		 
		uint8_t bFileNo = param->file_no;
		uint8_t Len[] = {sizeof(acd_ev1_t),0x00,0x00}; //LSB first!
		uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!
	
		uint16_t RxLen = 0;
	
		uint8_t RxData[64] = {0};
		uint8_t * pRxData = NULL;
		uint8_t rlen = 0;
		LOG2_PRINT("\nDESfire read data: \n");
		status = phalMfdfEVx_ReadData(
				pAlMfdfEVx,
				PHAL_MFDFEVX_COMMUNICATION_ENC,
				PHAL_MFDFEVX_APPLICATION_CHAINING,
				bFileNo,
				&Offset[0],
				&Len[0],
				&pRxData,
				&RxLen
				);
		if((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
			LOG2_PRINT("chaining\n");
			memcpy(RxData+rlen, pRxData, RxLen);
			rlen += RxLen;
			status = phalMfdfEVx_ReadData(
					pAlMfdfEVx,
					PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING,
					PHAL_MFDFEVX_APPLICATION_CHAINING,
					bFileNo,
					&Offset[0],
					&Len[0],
					&pRxData,
					&RxLen
					);
			if(status == PH_ERR_SUCCESS){
				memcpy(RxData+rlen, pRxData, RxLen);
				rlen += RxLen;
			}
		}
		CHECK_SUCCESS(status);
		if(status == PH_ERR_SUCCESS){
			LOG2_BUF_INF("\t", RxData, rlen);
			 acd_ev1_t* acd = (acd_ev1_t*)RxData;
			 reader_get_access_data(acd->customer_data, cred);
			 LOG2_DBG("wg: %d", cred->nbit);
			 LOG2_BUF_DBG("data", cred->credential, cred->clen);
		}
		else{
			return status;
		}	
		//		6. A WRITE command is performed on the Reissue Code field.
	{
		uint8_t data[1] = { 0 };
		uint16_t dlen = 0;
		uint8_t offset[3] = {0x0F, 0x00, 0x00};
		uint8_t length[3] = {1, 0x00, 0x00};
		LOG2_DBG("write data");
		status = phalMfdfEVx_WriteData(pAlMfdfEVx, 
			PHAL_MFDFEVX_COMMUNICATION_ENC, 
			PHAL_MFDFEVX_APPLICATION_CHAINING, 
			bFileNo, 
			offset, 
			data, 
			length
			);
		if((status != PH_ERR_SUCCESS) && ((status & PH_ERR_MASK) != PH_ERR_SUCCESS_CHAINING)){
			LOG2_ERR("phalMfdfEVx_WriteData fail: %04X", status);
			return status;
		}
	}
	{
		uint8_t end_apdu[] = {0x90, 0xC7, 0x00, 0x00, 0x00};
		uint8_t *end_rapdu;
		uint16_t end_rlen;
		LOG2_DBG("COMMIT TRANSACTION");
		status = phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);
		if(status){
			LOG2_ERR("phpalI14443p4_Exchange fail: %04X", status);
		}
	//7. DESELECT credential.
		phpalI14443p4_Deselect(ppalI14443p4);
	}
		return PH_ERR_SUCCESS;
}
phStatus_t reader_read_gw(credential_t* cred)
{
    phStatus_t status;

    uint8_t AID[] = {0xF5,0x32,0xF0};
    uint8_t ISODFName[] = {0xa0, 0x00, 0x00, 0x03, 0x96, 0x56, 0x43, 0x41, 0x03, 0xf5, 0x32, 0xf0, 0x00, 0x02, 0x09, 0x01};
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
    /* Clear the console. */
	log_reset_level();
    LOG2_DBG("A Ticket is discovered \n");

	
    /* SelectApplication */
    LOG2_PRINT("\nDESFire Select application.");
//	    status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, 0x00, &AID[0], NULL);
fci_info_t fci_info = {0};
{
	uint8_t *pFCI = NULL;
	uint16_t wFCILen = 0;
    status = phalMfdfEVx_IsoSelectFile(pAlMfdfEVx, 
    	PHAL_MFDFEVX_FCI_RETURNED, 
    	PHAL_MFDFEVX_SELECTOR_4,
    	NULL,
    	ISODFName, sizeof(ISODFName),
    	0,
    	&pFCI, &wFCILen
    	);
	if(status){
		LOG2_ERR("select err: %04X", status);
		return 1;
	}
	LOG2_BUF_DBG("FCI", pFCI, wFCILen);
	uint8_t len = wFCILen < sizeof(fci_info) ? wFCILen : sizeof(fci_info);
	memcpy(&fci_info, pFCI, len);
	reader_print_fci(&fci_info);
}

	uint8_t div[32] = {0};
	uint8_t dlen = reader_mf2go_gen_div(&fci_info, AID, div);
	uint8_t key_ver = google_wallet_key_entry.key_ver[0];
	LOG2_BUF_DBG("div", div, dlen);
	uint8_t key_no = 1;
	LOG2_INF("\nphalMfdfEVx_AuthenticateAES: \n");
    /*AES Authenticate First*/
    status = phalMfdfEVx_AuthenticateAES(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_DIV_METHOD_CMAC,
			GOOGLE_KEY_ID_AES,
            key_ver,
			key_no,
			div,
			dlen);
     CHECK_SUCCESS(status);
	 
	uint8_t bFileNo = 2;
	uint8_t Len[] = {sizeof(acd_ev1_t),0x00,0x00}; //LSB first!
	uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!

	uint16_t RxLen = 0;

	uint8_t RxData[64] = {0};
	uint8_t * pRxData = NULL;
	uint8_t rlen = 0;
	LOG2_INF("\nDESfire read data: \n");
	status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			PHAL_MFDFEVX_COMMUNICATION_ENC,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&Offset[0],
			&Len[0],
			&pRxData,
			&RxLen
			);
	if((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
		LOG2_PRINT("chaining\n");
		memcpy(RxData+rlen, pRxData, RxLen);
		rlen += RxLen;
		status = phalMfdfEVx_ReadData(
				pAlMfdfEVx,
				PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING,
				PHAL_MFDFEVX_APPLICATION_CHAINING,
				bFileNo,
				&Offset[0],
				&Len[0],
				&pRxData,
				&RxLen
				);
		if(status == PH_ERR_SUCCESS){
			memcpy(RxData+rlen, pRxData, RxLen);
			rlen += RxLen;
		}
	}
	CHECK_SUCCESS(status);
	if(status == PH_ERR_SUCCESS){
		LOG2_BUF_INF("\t", RxData, rlen);
		 acd_ev1_t* acd = (acd_ev1_t*)RxData;
		 reader_get_access_data(acd->customer_data, cred);
		 LOG2_DBG("wg: %d", cred->nbit);
		 LOG2_BUF_DBG("data", cred->credential, cred->clen);
	}
	else{
		return status;
	}	
	//		6. A WRITE command is performed on the Reissue Code field.
{
	uint8_t data[1] = { 0 };
	uint16_t dlen = 0;
	uint8_t offset[3] = {0x0F, 0x00, 0x00};
	uint8_t length[3] = {1, 0x00, 0x00};
	bFileNo = 2;
	LOG2_INF("write data");
	// ret = Reader_MFDF_WriteData(PHAL_MFDFEVX_COMMUNICATION_ENC, PHAL_MFDFEVX_APPLICATION_CHAINING, bFileNo, offset, data, length);
	status = phalMfdfEVx_WriteData(pAlMfdfEVx, 
		PHAL_MFDFEVX_COMMUNICATION_ENC, 
		PHAL_MFDFEVX_APPLICATION_CHAINING, 
		bFileNo, 
		offset, 
		data, 
		length
		);
	if((status != PH_ERR_SUCCESS) && ((status & PH_ERR_MASK) != PH_ERR_SUCCESS_CHAINING)){
		LOG2_ERR("phalMfdfEVx_WriteData fail: %04X", status);
		return status;
	}
}
{
	uint8_t end_apdu[] = {0x90, 0xC7, 0x00, 0x00, 0x00};
	uint8_t *end_rapdu;
	uint16_t end_rlen;
	LOG2_INF("COMMIT TRANSACTION");
//		void* pal14443a  = phNfcLib_GetDataParams(PH_COMP_PAL_ISO14443P4A);
	status = phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);
	if(status){
		LOG2_ERR("phpalI14443p4_Exchange fail: %04X", status);
	}
//7. DESELECT credential.
	phpalI14443p4_Deselect(ppalI14443p4);
}
    return PH_ERR_SUCCESS;
}


//获取分散因子
static int reader_read_aw_div(key_set_t* key_set, uint8_t* div, uint8_t* dlen){
	phStatus_t status;
	int ret;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
//2. SELECT the Privacy application and authenticate using the undiversified key.
	uint8_t AID[3];
	memcpy(AID, &key_set->aid, 3);
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, AID, NULL);
	if(status){
		LOG2_ERR("select app1 fail: %04X", status);
		return 1;
	}

	LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
	uint8_t key_no = key_set->key_no;
    /*AES Authenticate First*/
    status = phalMfdfEVx_Authenticate(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_NO_DIVERSIFICATION,
			APPLE_KEY_ID_DES,
            0x00,
			key_no,
			NULL,
			0);
     CHECK_SUCCESS(status);

	status = phalMfdfEVx_GetCardUID(pAlMfdfEVx, 
		PHAL_MFDFEVX_GET_CARD_UID_EXCHANGE_OPTION_OFF,
		PHAL_MFDFEVX_GET_CARD_UID_OPTION_NUID_NOT_RETURNED,
		div);
	CHECK_SUCCESS(status);
	*dlen = 7;
	LOG2_BUF_DBG("uid:", div, 7);
	return status;
}

static int reader_read_aw_data(w_apple_wallet_param_t* param, uint8_t* div, uint8_t div_len, uint8_t* rdata, uint8_t* rlen){
	phStatus_t status;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
	key_set_t* key_set = &param->key_set[1];
	LOG2_PRINT("\nphalMfdfEVx_SelectApplication 2: \n");
	uint8_t AID[3];
	memcpy(AID, &key_set->aid, 3);
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, AID, NULL);
	CHECK_SUCCESS(status);
	
	LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
    /*AES Authenticate First*/
    status = phalMfdfEVx_AuthenticateAES(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_DIV_METHOD_CMAC,
			APPLE_KEY_ID_AES,
            0x00,
			key_set->key_no,
			div,
			div_len);
     CHECK_SUCCESS(status);
	 
	uint8_t bFileNo = 1;
	uint8_t Len[] = {16,0x00,0x00}; //LSB first!
	uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!

	uint16_t RxLen = 0;

	uint8_t RxData[64] = {0};
	uint8_t * pRxData = NULL;
	uint8_t rxlen = 0;
	LOG2_PRINT("\nDESfire read data: \n");
	status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			PHAL_MFDFEVX_COMMUNICATION_ENC,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&Offset[0],
			&Len[0],
			&pRxData,
			&RxLen
			);
	if((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
		LOG2_PRINT("chaining\n");
		memcpy(RxData+rxlen, pRxData, RxLen);
		rxlen += RxLen;
		status = phalMfdfEVx_ReadData(
				pAlMfdfEVx,
				PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING,
				PHAL_MFDFEVX_APPLICATION_CHAINING,
				bFileNo,
				&Offset[0],
				&Len[0],
				&pRxData,
				&RxLen
				);
		if(status == PH_ERR_SUCCESS){
			memcpy(RxData+rxlen, pRxData, RxLen);
			rxlen += RxLen;
		}
	}
	CHECK_SUCCESS(status);
	LOG2_BUF_INF("\t", RxData, rxlen);
	memcpy(rdata, RxData, rxlen);
	*rlen = rxlen;
	//		6. A WRITE command is performed on the Reissue Code field.

{
	uint8_t end_apdu[] = {0x90, 0xEE, 0x00, 0x00, 0x00};
	uint8_t *end_rapdu;
	uint16_t end_rlen;
	LOG2_DBG("COMMIT TRANSACTION");
	status = phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);
	if(status){
		LOG2_ERR("phpalI14443p4_Exchange fail: %04X", status);
	}
//7. DESELECT credential.
	phpalI14443p4_Deselect(ppalI14443p4);
}
    return PH_ERR_SUCCESS;
}

static uint32_t reader_read_apple_wallet(w_apple_wallet_param_t* param, credential_t* cred){
	int ret;
	uint8_t div[8];
	uint8_t div_len = 0;
	//获取分散因子
	ret = reader_read_aw_div(&param->key_set[0], div, &div_len);
	if(ret){
		return ret;
	}
	uint8_t rdata[32];
	uint8_t rlen = 0;
	//读数据
	ret = reader_read_aw_data(param, div, div_len, rdata, &rlen);
	if(ret){
		return ret;
	}
	uint8_t size = 5;
	memcpy(cred->credential, rdata, size);
	cred->clen = size;
	cred->nbit = size * 8;
	return 0;
}

phStatus_t reader_read_aw(credential_t* cred)
{
    phStatus_t status;
	uint8_t uid[8] = {0};
	uint8_t ulen;
    uint8_t AID[] = {0x00,0x1E,0xA1};
    uint8_t AID2[] = {0x01,0x1E,0xA1};
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
    /* Clear the console. */
	log_reset_level();
    LOG2_DBG("A Ticket is discovered \n");

	
    /* SelectApplication */
    LOG2_PRINT("\nDESFire Select application.");
//2. SELECT the Privacy application and authenticate using the undiversified key.
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, AID, NULL);
	if(status){
		LOG2_ERR("select app1 fail: %04X", status);
		return 1;
	}

	LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
	uint8_t key_no = 0;
    /*AES Authenticate First*/
    status = phalMfdfEVx_Authenticate(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_NO_DIVERSIFICATION,
			APPLE_KEY_ID_DES,
            0x00,
			key_no,
			NULL,
			0);
     CHECK_SUCCESS(status);

	status = phalMfdfEVx_GetCardUID(pAlMfdfEVx, 
		PHAL_MFDFEVX_GET_CARD_UID_EXCHANGE_OPTION_OFF,
		PHAL_MFDFEVX_GET_CARD_UID_OPTION_NUID_NOT_RETURNED,
		uid);
	CHECK_SUCCESS(status);
	ulen = 7;
	LOG2_BUF_DBG("uid:", uid, 7);
	LOG2_PRINT("\nphalMfdfEVx_SelectApplication 2: \n");
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, PHAL_MFDFEVX_SELECT_PRIMARY_APP, AID2, NULL);
	CHECK_SUCCESS(status);
	
	LOG2_PRINT("\nphalMfdfEVx_AuthenticateAES: \n");
    /*AES Authenticate First*/
    status = phalMfdfEVx_AuthenticateAES(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_DIV_METHOD_CMAC,
			APPLE_KEY_ID_AES,
            0x00,
			key_no,
			uid,
			ulen);
     CHECK_SUCCESS(status);
	 
	uint8_t bFileNo = 1;
	uint8_t Len[] = {16,0x00,0x00}; //LSB first!
	uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!

	uint16_t RxLen = 0;

	uint8_t RxData[64] = {0};
	uint8_t * pRxData = NULL;
	uint8_t rlen = 0;
	LOG2_PRINT("\nDESfire read data: \n");
	status = phalMfdfEVx_ReadData(
			pAlMfdfEVx,
			PHAL_MFDFEVX_COMMUNICATION_ENC,
			PHAL_MFDFEVX_APPLICATION_CHAINING,
			bFileNo,
			&Offset[0],
			&Len[0],
			&pRxData,
			&RxLen
			);
	if((status & PH_ERR_MASK) == PH_ERR_SUCCESS_CHAINING){
		LOG2_PRINT("chaining\n");
		memcpy(RxData+rlen, pRxData, RxLen);
		rlen += RxLen;
		status = phalMfdfEVx_ReadData(
				pAlMfdfEVx,
				PHAL_MFDFEVX_COMMUNICATION_ENC|PH_EXCHANGE_RXCHAINING,
				PHAL_MFDFEVX_APPLICATION_CHAINING,
				bFileNo,
				&Offset[0],
				&Len[0],
				&pRxData,
				&RxLen
				);
		if(status == PH_ERR_SUCCESS){
			memcpy(RxData+rlen, pRxData, RxLen);
			rlen += RxLen;
		}
	}
	CHECK_SUCCESS(status);
	LOG2_BUF_INF("\t", RxData, rlen);
	
	memcpy(cred->credential, RxData, rlen);
	cred->clen = rlen;
	//		6. A WRITE command is performed on the Reissue Code field.

{
	uint8_t end_apdu[] = {0x90, 0xEE, 0x00, 0x00, 0x00};
	uint8_t *end_rapdu;
	uint16_t end_rlen;
	LOG2_DBG("COMMIT TRANSACTION");
	status = phpalI14443p4_Exchange(ppalI14443p4, PH_EXCHANGE_DEFAULT, end_apdu, sizeof(end_apdu), &end_rapdu, &end_rlen);
	if(status){
		LOG2_ERR("phpalI14443p4_Exchange fail: %04X", status);
	}
//7. DESELECT credential.
	phpalI14443p4_Deselect(ppalI14443p4);
}
    return PH_ERR_SUCCESS;
}


int reader_read_wavelynx_tag(Reader_T* read, credential_t* cred){
#if 0
	int ret = reader_read_apple_wallet(&apple_wallet_param, cred);
	if(!ret){
		return ret;
	}
	if(ret != 1){
		return ret;
	}
	return reader_read_google_wallet(&mf2go_param, cred);
#endif 
	int ret = reader_read_aw(cred);
	if(!ret){
		return ret;
	}
	return reader_read_gw(cred);
}

/************************************************************************************************/

#pragma pack(1)

//公共文件
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t type;		//类型：0 - 用户配置卡。1 - 授权卡。2 - 厂商配置卡。3 - 激活卡。	
	uint8_t isser_code[16];//厂商信息
	uint8_t cmac[8];
}card_info_t;

typedef struct {
	uint8_t key_id;
	uint8_t key_ver;
	uint8_t key_type;
	uint8_t key_val[32];
}key_t;

//配置卡密钥
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t isser_code[16];//验证码
	uint8_t key_num;
	key_t keys[8];
	uint8_t cmac[8];
}cfg_keys_t;
//密钥数据
typedef struct {
	uint16_t version;	//版本
	uint32_t time;		//写卡时间
	uint8_t key_num;
	key_t keys[8];
	uint8_t cmac[8];
}key_data_t;

#pragma pack()


//生成DIV
static void reader_cfg_gen_div(uint8_t uid[], uint32_t aid, uint8_t div[16]){
	uint8_t buf[16];
	memset(buf, 0, sizeof(buf));
	memcpy(buf, uid, 7);
	buf[8] = aid >> 16;
	buf[9] = aid >> 8;
	buf[10] = aid;
	memcpy(div, buf, 16);
}


//配置卡
int reader_wavelynx_config_tag(credential_t* cred)
{
    phStatus_t status;

	uint32_t aid = 0xCF0001;
	phalMfdfEVx_SamAV3_NonX_DataParams_t *pAlMfdfEVx = &palMfdfEVx;
    /* Clear the console. */
	log_reset_level();
    LOG2_DBG("A Ticket is discovered \n");
	
    /* SelectApplication */
    LOG2_PRINT("\nDESFire Select application.");
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, 0x00, (uint8_t*)&aid, NULL);
	CHECK_SUCCESS(status);

	uint8_t key_no = 1;
	uint8_t key_ver = 1;
	LOG2_INF("\nphalMfdfEVx_AuthenticateAES: \n");
    /*AES Authenticate First*/
    status = phalMfdfEVx_AuthenticateAES(
    		pAlMfdfEVx,
    		PHAL_MFDFEVX_NO_DIVERSIFICATION,
			1,
            key_ver,
			key_no,
			NULL,
			0);
     CHECK_SUCCESS(status);

	 card_info_t card_info;
	 uint8_t bFileNo = 0;
	 uint8_t Len[] = {sizeof(card_info_t),0x00,0x00}; //LSB first!
	 uint8_t Offset[] = {0x00,0x00,0x00};//LSB first!
 
	 uint16_t RxLen = 0;
 
	 uint8_t RxData[64] = {0};
	 uint8_t * pRxData = NULL;
	 uint8_t rlen = 0;
	 LOG2_PRINT("\nDESfire read data: \n");
	 status = phalMfdfEVx_ReadData(
			 pAlMfdfEVx,
			 PHAL_MFDFEVX_COMMUNICATION_ENC,
			 PHAL_MFDFEVX_APPLICATION_CHAINING,
			 bFileNo,
			 &Offset[0],
			 &Len[0],
			 &pRxData,
			 &RxLen
			 );
	CHECK_SUCCESS(status);

	uint8_t div[16] = {0};
	reader_cfg_gen_div(cred->tag.uid, aid, div);
	uint8_t* info = pRxData;
	uint8_t ilen = RxLen-8;
	LOG2_BUF_DBG("info:", info, ilen);
	uint8_t* imac = info + ilen;
	LOG2_BUF_DBG("imac:", imac, 8);
	LOG2_BUF_DBG("div:", div, 16);
	uint8_t iv[16] = {0};
	//装载IV
#if 0
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_LoadInitVector(
		&stHal_SamAv3,
		PHHAL_HW_SAMAV3_CMD_SAM_LOAD_IV_MODE_SET_IV,
		iv,
		16));
#endif 
	//激活mac密钥
	/* Perform Offline activation. */
 PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_ActivateOfflineKey(
 	&stHal_SamAv3,
 	PHHAL_HW_SAMAV3_CMD_SAM_AO_LRP_UPDATE_KEY_RFU,
 	(uint8_t) 3,
 	(uint8_t) 1,
 	div,
 	16));
#if 0
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_ActivateOfflineKey(
		&stHal_SamAv3,
		PHHAL_HW_SAMAV3_CMD_SAM_AO_LRP_UPDATE_KEY_RFU,
		(uint8_t) 3,
		(uint8_t) 1,
		NULL,
		0));
#endif 
	uint8_t* pResponse = NULL;
	uint16_t wRespLen = 0;
	
	/* Generate the MAC. */
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_GenerateMAC(
		&stHal_SamAv3,
		PH_EXCHANGE_DEFAULT,
		0x08,
		info,
		ilen,
		&pResponse,
		&wRespLen));
#if 0
	uint8_t data[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
		0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16};
	/* Generate the MAC. */
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_GenerateMAC(
		&stHal_SamAv3,
		PH_EXCHANGE_DEFAULT,
		0x08,
		data,
		sizeof(data),
		&pResponse,
		&wRespLen));
#endif 
	LOG2_BUF_DBG("mac:", pResponse, wRespLen);
	if(memcmp(pResponse, imac, 8)){
		LOG2_ERR("mac check fail");
		return 1;
	}
	//选择应用 CF0002
	aid = 0xCF0002;
	LOG2_PRINT("\n Select application: %X\n", aid);
	status = phalMfdfEVx_SelectApplication(pAlMfdfEVx, 0x00, (uint8_t*)&aid, NULL);
	CHECK_SUCCESS(status);
    
	key_ver = 1;
	key_no = 1;
	reader_cfg_gen_div(cred->tag.uid, aid, div);
	LOG2_BUF_DBG("div:", div, 16);
    status = phalMfdfEVx_AuthenticateAES(
		pAlMfdfEVx,
		PHAL_MFDFEVX_DIV_METHOD_CMAC,
		2,
		key_ver,
		key_no,
		div,
		16);
	CHECK_SUCCESS(status);		
    return PH_ERR_SUCCESS;
}

int reader_wavelynx_gen_mac(void)
{
	phStatus_t status;
	uint8_t div[] = {0x04,0x54,0x35,0xAA,0x52,0x4D,0x80,0x00,0xCF,0x00,0x01,0x00,0x00,0x00,0x00,0x00};
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_ActivateOfflineKey(
		&stHal_SamAv3,
		PHHAL_HW_SAMAV3_CMD_SAM_AO_LRP_UPDATE_KEY_RFU,
		(uint8_t) 3,
		(uint8_t) 1,
		div,
		sizeof(div)));
	uint8_t* pResponse = NULL;
	uint16_t wRespLen = 0;

#if 0
	uint8_t data[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,
		0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16};
	uint8_t vmac[] = {0x99,0x4F,0x7D,0x6D,0x10,0x04,0x35,0xC2};
#else
	uint8_t data[] = {0x00,0x01,0xFF,0xF3,0xD0,0x67,0x03,0x5A,0x4B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
	uint8_t vmac[] = {0x76,0x48,0xF0,0xEB,0x69,0x4A,0xC6,0x07};
#endif 
	/* Generate the MAC. */
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_GenerateMAC(
		&stHal_SamAv3,
		PH_EXCHANGE_DEFAULT,
		0x08,
		data,
		sizeof(data),
		&pResponse,
		&wRespLen));
	LOG2_BUF_DBG("mac:", pResponse, wRespLen);
	if(memcmp(pResponse, vmac, 8)){
		LOG2_ERR("mac check fail");
		return 1;
	}
	//校验MAC
	LOG2_INF("verify mac");
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_ActivateOfflineKey(
		&stHal_SamAv3,
		PHHAL_HW_SAMAV3_CMD_SAM_AO_LRP_UPDATE_KEY_RFU,
		(uint8_t) 3,
		(uint8_t) 1,
		div,
		sizeof(div)));
	uint8_t buf[] = {
		0x00,0x01,0xFF,0xF3,0xD0,0x67,0x03,0x5A,0x4B,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x76,0x48,0xF0,0xEB,0x69,0x4A,0xC6,0x07
		};
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SamAV3_Cmd_SAM_VerifyMAC(
		&stHal_SamAv3,
		PH_EXCHANGE_DEFAULT,
		0x08,
		buf,
		sizeof(buf)));
	
	LOG2_INF("verify mac ok");
	return 0;
}

/***********************************************************************************************
*                            End Of File
**********************************************************************************************/

